Skip to content

fix(cloudflare): resolve D1 databases by name without total_pages - #3095

Open
dchaudhari7177 wants to merge 2 commits into
emdash-cms:mainfrom
dchaudhari7177:fix/2840-d1-name-lookup-paging
Open

dchaudhari7177 wants to merge 2 commits into
emdash-cms:mainfrom
dchaudhari7177:fix/2840-d1-name-lookup-paging

Conversation

@dchaudhari7177

Copy link
Copy Markdown
Contributor

What does this PR do?

emdash migrate --d1 <name> could never resolve a name. databaseByName validated pagination with listInteger(value.total_pages, …), but the D1 list endpoint's result_info is { count, page, per_page, total_count } with no total_pages, so every lookup threw Cloudflare D1 database list total_pages is invalid. before looking at a single row. UUIDs and --wrangler-config were unaffected.

  • Page count. When total_pages is absent, it is derived as ceil(total_count / per_page). When present it is validated as before. Everything downstream (the page loop, the cross-page consistency check, MAX_DATABASE_LIST_PAGES, the final seenCount === totalCount check) is unchanged and now runs on a value the endpoint actually implies.
  • Substring matches (the issue's secondary note). name is a substring filter, and every row went through metadataDatabase before the exact-name filter. That throws for any non-production row, so once paging worked, a preview site-db-staging on the same page would still have failed the lookup for site-db. Rows are now filtered by exact name first, and only the matches are validated as deployment targets.

Closes #2840

Type of change

  • Bug fix

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes: tsc --noEmit -p packages/cloudflare reports the same 7 errors on this branch and on main (unbuilt emdash workspace types), none in the touched file
  • pnpm lint passes: oxlint --deny-warnings on the touched files
  • pnpm test passes (or targeted tests for my change): see below
  • pnpm format has been run: oxfmt
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation: n/a
  • I have added and reviewed the user-facing changeset
  • New features link to an approved Discussion: n/a, bug fix
  • I have included screenshots below if this PR changes the UI: n/a

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 5 (Claude Code)

Screenshots / test output

Not applicable (CLI). The test stub listApiResponse synthesized total_pages, which is why CI never saw this. The new cases in packages/cloudflare/tests/db/d1-migration-target.test.ts use a liveListApiResponse shaped like the endpoint the issue recorded:

  • resolves a name from a single page;
  • walks two pages derived from total_count: 2, per_page: 1;
  • ignores a preview site-db-staging listed next to site-db;
  • still reports No D1 database named site-db for an empty result.
main:  5 failed | 10 passed   # the 4 new cases ("total_pages is invalid") + 1 pre-existing
head:  1 failed | 14 passed   # only the pre-existing one

The one failure on both trees is uses the selected Wrangler environment and its own binding array, which asserts /project/wrangler.jsonc and gets a Windows path separator on this machine. CI on Linux should pass it. I did not run this against the live Cloudflare API.

databaseByName required result_info.total_pages, which the D1 list
endpoint never returns, so every --d1 <name> lookup failed with
"total_pages is invalid". Derive the page count from total_count and
per_page when the field is absent. The test stub synthesized total_pages,
which is why CI passed; add cases using the live envelope.

The endpoint's name parameter is a substring filter, and every row was
validated as a production deployment target before the exact-name filter,
so a preview database named site-db-staging failed the lookup for
site-db. Filter by exact name first.

Closes emdash-cms#2840
@changeset-bot

changeset-bot Bot commented Sep 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4839bac

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@emdash-cms/cloudflare Patch
@emdash-cms/plugin-test Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
emdash Patch
create-emdash Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/release-service Patch
@emdash-cms/plugin-embeds Patch
@emdash-cms/sandbox-workerd Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR fixes a real, well-scoped bug: emdash migrate --d1 <name> failed because the Cloudflare D1 list endpoint does not return total_pages, so the strict validator rejected every name lookup before any row was inspected. The fix derives the page count from total_count / per_page when total_pages is absent, and the secondary improvement filters rows by exact name before calling the deployment-target validator, preventing substring-match preview databases from aborting an otherwise valid lookup.

The approach is correct and narrowly targeted: only databaseByName changes, the --d1 <uuid> and --wrangler-config paths are untouched, and the existing envelope shape (with total_pages) continues to be accepted and validated exactly as before. I checked the new listResultInfo logic, the pagination validation guard (totalPages === 0 special case, MAX_DATABASE_LIST_PAGES, seenCount === totalCount), and the filter-before-validate ordering. The boundary cases I traced (empty result, single page, multi-page walk, exact-name match, exact-name preview match, substring preview/development match) all behave correctly.

The added test cases exercise the live envelope without total_pages, including multi-page derivation and the preview-substring case, and the existing tests continue to cover the legacy envelope. The changeset names the affected command and pins the exact error message a user would see, which meets the .changeset/README.md standard. No AGENTS.md conventions are violated: no content-table queries, no auth/UI/locale changes, no new logged-out hot-path queries, and the added comments explain the non-obvious API behavior / validation ordering without referencing PRs or issue numbers.

Clean fix with good coverage — LGTM.

@pkg-pr-new

pkg-pr-new Bot commented Sep 13, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@3095

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@3095

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@3095

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@3095

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@3095

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@3095

emdash

npm i https://pkg.pr.new/emdash@3095

create-emdash

npm i https://pkg.pr.new/create-emdash@3095

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@3095

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@3095

@emdash-cms/plugin-test

npm i https://pkg.pr.new/@emdash-cms/plugin-test@3095

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@3095

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@3095

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@3095

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/@emdash-cms/registry-moderation@3095

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@3095

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@3095

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@3095

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@3095

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@3095

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@3095

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@3095

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@3095

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@3095

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@3095

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@3095

commit: 05a0e3d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

emdash migrate --d1 <name> always fails: Cloudflare's D1 list API omits result_info.total_pages

2 participants